package example.Kamera;

//  -------------   JOGL SampleProgram  (Pyramide) ------------
//Kantenmodell, Sichtbarkeit ist noch nicht beruecksichtigt
//MyThird, aber zurueckgestellt wieder, d.h. keine 2 Pyramide und keine Kante
//z Buffer Test schaut, falls ein neuer Punkt gezeichnet wird, wird getestet ob der neue Punkt ueberhaupt
//gezeichnet werden muss, oder ob der existierende Punkt den neuen Punkt verdeckt
//--> muessen den Z-Buffer im init aktivieren
//Problem im Kantenmodell verdeckt kein Punkt den anderen, d.h. aktivieren des Z-Buffers
//hat keinen Effekt. Wir zeichnen also nochmals eine Pyramide aber ausgemalt.
//Wichtig beim zeichnen der Figur muessen wir den Z-Buffer immer wieder loeschen

import javax.media.opengl.*;
import com.sun.opengl.util.*;
import java.awt.*;
import java.awt.event.*;

public class MySecond_Sichtbarkeit implements WindowListener, GLEventListener, KeyListener {

	GLCanvas canvas; // OpenGl-Canvas
	double left = -10, right = 10; // Koordinatenbereich
	double bottom, top; // werden in reshape gesetzt
	double near = -100, far = 100; // Clipping Bereich
	//viewing volumen vergroessen, heist clipping bereich vergroessen
	double elev = 20; // Elevation Kamera-System
	double azim = 30; // Azimut Kamera-System

	// ------------------ Methoden --------------------

	void zeichneAchsen(GL gl, double a) // Koordinatenachsen zeichnen
	{
		gl.glBegin(GL.GL_LINES);
		gl.glVertex3d(0, 0, 0);
		gl.glVertex3d(a, 0, 0);
		gl.glVertex3d(0, 0, 0);
		gl.glVertex3d(0, a, 0);
		gl.glVertex3d(0, 0, 0);
		gl.glVertex3d(0, 0, a);
		gl.glEnd();
	}

	/**
	 * pyramide wird im standard system gezeichnet
	 * 
	 * @param gl
	 * @param a
	 * @param h
	 */
	void zeichnePyramide(GL gl, double a, double h) // Pyramide zeichnen
	{
		gl.glBegin(GL.GL_POLYGON); // Boden
		gl.glVertex3d(a, 0, a);
		gl.glVertex3d(a, 0, -a);
		gl.glVertex3d(-a, 0, -a);
		gl.glVertex3d(-a, 0, a);
		gl.glEnd();
		//fuellen eine Seitenflaeche komplett aus
//		gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL);
		gl.glBegin(GL.GL_POLYGON); // Seitenflaechen
		gl.glVertex3d(a, 0, a);
		gl.glVertex3d(a, 0, -a);
		gl.glVertex3d(0, h, 0);
		gl.glEnd();
//		gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE);
		gl.glBegin(GL.GL_POLYGON);
		gl.glVertex3d(a, 0, -a);
		gl.glVertex3d(-a, 0, -a);
		gl.glVertex3d(0, h, 0);
		gl.glEnd();
		gl.glBegin(GL.GL_POLYGON);
		gl.glVertex3d(-a, 0, -a);
		gl.glVertex3d(-a, 0, a);
		gl.glVertex3d(0, h, 0);
		gl.glEnd();
		gl.glBegin(GL.GL_POLYGON);
		gl.glVertex3d(-a, 0, a);
		gl.glVertex3d(a, 0, a);
		gl.glVertex3d(0, h, 0);
		gl.glEnd();
	}

	public MySecond_Sichtbarkeit() // Konstruktor
	{
		Frame f = new Frame("MySecond");
		canvas = new GLCanvas(); // OpenGL-Window
		f.setSize(800, 600);
		f.setBackground(Color.gray);
		f.addWindowListener(this);
		canvas.addGLEventListener(this);
		canvas.addKeyListener(this);
		f.add(canvas);
		f.setVisible(true);
		canvas.requestFocus();
	}

	public static void main(String[] args) // main-Methode der Applikation
	{
		new MySecond_Sichtbarkeit();
	}

	// --------- OpenGL-Events -----------------------

	public void init(GLAutoDrawable drawable) {
		GL gl = drawable.getGL(); // OpenGL-Objekt
		gl.glClearColor(0.0f, 0.0f, 1.0f, 1.0f); // erasing color
		//aktivieren des z Buffers
		gl.glEnable(GL.GL_DEPTH_TEST);
		//aktivieren des Polygon Offset
		gl.glEnable(GL.GL_POLYGON_OFFSET_FILL);
		//zu den Z-Werten wir ein Offset hinzugefuegt, so das die Z Werte nicht die gleichen Werte haben
		gl.glPolygonOffset(1,1);
	}

	/**
	 * Erst wird das Kamerasystem bewegt mit absoluten Bewegungen
	 * danach wird das Objektsystem bewegt, aber mit relativen Bewegungen
	 * d.h. bei der Drehung geht man von der momentanen Lage des Objekts auf
	 * 
	 */
	public void display(GLAutoDrawable drawable) {
		GL gl = drawable.getGL();
//		gl.glClear(GL.GL_COLOR_BUFFER_BIT);  //loescht nur Bild
		// Bild loeschen und auch noch den z Buffer loeschen
		gl.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT);
		gl.glColor3d(0, 1, 1); // Zeichenfarbe
		gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE); // Polygon
															// Zeichen-Modus
		gl.glMatrixMode(GL.GL_MODELVIEW);
		gl.glLoadIdentity(); // Kamera-System positionieren:
		//deaktivieren wir rotate, dann muesten wir von vorne auf die pyramide sehen
		//also die front
		gl.glTranslated(0, 0, -2); //Kamera vom System weg bewegen, hat aber fuer die orthogonale Projektion keine Wirkung, erst wenn die eleveation dazu kommt spielt dies eine Rolle
		//wichtig elevation nach dem translate;
		//notizen: ensrpicht der 1 Variante: absolute Variante
		gl.glRotated(elev, 1, 0, 0); // Drehung um x-Achse
		gl.glRotated(-azim, 0, 1, 0); // Drehung um y-Achse
//		//2 Variante, wir vertauschen die Operatione, muesste so wie im Objektsystem relativ interpretiert werden: falsche Variante
//		gl.glRotated(-azim, 0, 1, 0); // Drehung um y-Achse
//		gl.glRotated(elev, 1, 0, 0); // Drehung um x-Achse
		zeichneAchsen(gl, 1);
		gl.glColor3d(0,0,1);
		gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_FILL);
		zeichnePyramide(gl, 4, 4);
		gl.glColor3d(0,1,1);
		//wir zeichnen nochmal die Pyramide aber in der Hintergrundfarbe, um Sichtbarkeit zu demonstrieren
		gl.glPolygonMode(GL.GL_FRONT_AND_BACK, GL.GL_LINE);
		zeichnePyramide(gl, 4, 4);
	}

	public void reshape(GLAutoDrawable drawable, // Window resized
			int x, int y, int width, int height) {
		GL gl = drawable.getGL();
		double yxRatio = (float) height / width; // aspect-ratio
		bottom = yxRatio * left;
		top = yxRatio * right;
		gl.glMatrixMode(GL.GL_PROJECTION);
		gl.glLoadIdentity();
		gl.glOrtho(left, right, bottom, top, near, far); // Viewing-Volume (im
															// Raum)
		gl.glViewport(0, 0, width, height);
	}

	public void displayChanged(GLAutoDrawable drawable, boolean modeChanged,
			boolean deviceChanged) {
	}

	// --------- Window-Events --------------------

	public void windowClosing(WindowEvent e) {
		System.exit(0);
	}

	public void windowActivated(WindowEvent e) {
	}

	public void windowClosed(WindowEvent e) {
	}

	public void windowDeactivated(WindowEvent e) {
	}

	public void windowDeiconified(WindowEvent e) {
	}

	public void windowIconified(WindowEvent e) {
	}

	public void windowOpened(WindowEvent e) {
	}

	@Override
	public void keyPressed(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_UP:
			elev++;
			canvas.repaint();
			break;
		case KeyEvent.VK_DOWN:
			elev--;
			canvas.repaint();
			break;
		case KeyEvent.VK_LEFT:
				azim++;
				canvas.repaint();
			break;
		case KeyEvent.VK_RIGHT:
				azim--;
				canvas.repaint();
			break;	
		default:
			break;
		}
		
	}

	@Override
	public void keyReleased(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		// TODO Auto-generated method stub
		
	}

}
